package cn.sunshine.basic.service.impl;

import cn.sunshine.basic.constant.BaseContants;
import cn.sunshine.basic.dto.RegisterDto;
import cn.sunshine.basic.exception.BusinessException;
import cn.sunshine.basic.service.IVerifyCodeService;
import cn.sunshine.basic.utils.StrUtils;
import cn.sunshine.basic.utils.VerifyCodeUtils;
import cn.sunshine.user.domain.User;
import cn.sunshine.user.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.concurrent.TimeUnit;

@Service
public class VerifyCodeServiceImpl implements IVerifyCodeService {
    // 注入Redis对象使用
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private UserMapper userMapper;

    @Override
    public String grap(String key) {
        // 判断传递的参数是否为空，为空就抛出异常
        if (StringUtils.isEmpty(key)) {
            throw new BusinessException("请传递正确的参数");
        }
        // 使用字符串工具类生成4位随机码
        String code = StrUtils.getComplexRandomString(4);
        // 将4位随机字符串存到Redis中并设置过期时间5分钟
        redisTemplate.opsForValue().set(key, code, 5, TimeUnit.MINUTES);
        // 将生成的随机字符串生成图形并编码成base64
        String base64Str = VerifyCodeUtils.VerifyCode(100, 35, code);
        return base64Str;
    }

    @Override
    public void smsCode(RegisterDto registerDto) {
        // 1.获取手机号，图形验证码的RedisKey，图形验证码
        String phone = registerDto.getPhone();
        // 业务类型type
        String type = registerDto.getType();
        // 2.参数非空判断。
        if (StringUtils.isEmpty(phone) || StringUtils.isEmpty(type)) {
            throw new BusinessException("请传递正确的参数");
        }
        // 3.判断业务的走向
        if ("register".equals(type)) {
            // 校验图形验证码是否正确
            checkImageCode(registerDto);
            //3.判断用户是否已注册，如果已注册提示用户
            User user = userMapper.loadByPhone(phone);
            if (user != null) {
                throw new BusinessException("用户已注册，请直接登录，如果忘记密码，请点击忘记密码！");
            }
            sendCode(BaseContants.verifyCodeConstant.BUSINESS_REGISTER_KEY, phone);
        } else if ("binder".equals(type)) { // 2.2.微信绑定账号业务,发送短信验证码
            sendCode(BaseContants.verifyCodeConstant.BUSINESS_BINDER_KEY, phone);
        }
    }

        /*
         * @Title: smsCode
         * @Description: 发送手机验证码
         * @Author: Mr.Jiang
         * @Version: 1.0
         * @Date:  2022/7/11 0:05
         * @Parameters: [registerDto]
         * @Return void
         */

    private void sendCode(String businessKey, String phone) {
            //4.根据电话号码拼接业务键，去redis中获取对应的value值，判断是否存在
            String phoneCodeKey = businessKey + phone;
            Object phoneCodeValue = redisTemplate.opsForValue().get(phoneCodeKey);
            //0.定义一个空字符串，专门用来接收验证码
            String phoneCode = "";
            if (phoneCodeValue == null) {//1.不存在
                //1.生成新的随机验证码,并赋值给空字符串
                phoneCode = StrUtils.getComplexRandomString(4);
            } else {//2.存在
                //1.分割value得到时间戳，跟现在的时间戳做减法，如果小于1分钟的毫秒数抛出异常
                String[] phoneCodeValueTmp = phoneCodeValue.toString().split(":");
                // 之前存入code时，我们记录的时间戳
                Long oldTime = Long.valueOf(phoneCodeValueTmp[1]);
                System.out.println(oldTime);
                // 现在的时间戳
                Long nowTime = System.currentTimeMillis();
                if (nowTime - oldTime < 1 * 60 * 1000) {
                    throw new BusinessException("请一分钟之后再获取！");
                }
                //2.将旧的验证码赋值给空字符串
                phoneCode = phoneCodeValueTmp[0];
            }
            //5.通过业务键+phone作为key，验证码+时间戳作为value，存入redis，设置为三分钟有效
            String phoneCodeRedis = System.currentTimeMillis() + ":" + phoneCode;
            redisTemplate.opsForValue().set(phoneCodeKey, phoneCodeRedis, 3, TimeUnit.MINUTES);
            //6.发送短信验证码
            // SmsUtils.sendCode(phone, "亲，您的验证码是："+ phoneCode);
            System.out.println("亲，您的验证码是：" + phoneCode);
        }



    /*
     * @Title: checkImageCode
     * @Description: 图形验证码校验
     * @Author: Mr.Jiang
     * @Version: 1.0
     * @Date:  2022/7/11 0:11
     * @Parameters: [registerDto]
     * @Return void
     */
    private void checkImageCode(RegisterDto registerDto) {
        // 图形验证码的key
        String imageCodeKey = registerDto.getImageCodeKey();
        // 图形验证码的value
        String imageCodeValue = registerDto.getImageCodeValue();
        //1.非空校验
        if (StringUtils.isEmpty(imageCodeKey) || StringUtils.isEmpty(imageCodeValue)) {
            throw new BusinessException("参数不能为空！");
        }
        //2.判断图形验证码是否正确以及存在
        Object imageCodeValueTmp = redisTemplate.opsForValue().get(imageCodeKey);
        if (imageCodeValueTmp == null) {
            throw new BusinessException("验证码已过期，请重新获取！");
        }
        // 忽略大小写比较图形验证码是否正确
        if (!imageCodeValueTmp.toString().equalsIgnoreCase(imageCodeValue)) {
            throw new BusinessException("验证码错误，请重新输入！");
        }
    }
}
